{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# python notebook for Make Your Own Neural Network\n",
    "# code for a 3-layer neural network, and code for learning the MNIST dataset\n",
    "# this version trains using the MNIST dataset, then tests on our own images\n",
    "# (c) Tariq Rashid, 2016\n",
    "# license is GPLv2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy\n",
    "# scipy.special for the sigmoid function expit()\n",
    "import scipy.special\n",
    "# library for plotting arrays\n",
    "import matplotlib.pyplot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# helper to load data from PNG image files\n",
    "import imageio.v3\n",
    "# glob helps select multiple files using patterns\n",
    "import glob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# neural network class definition\n",
    "class neuralNetwork:\n",
    "    \n",
    "    \n",
    "    # initialise the neural network\n",
    "    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):\n",
    "        # set number of nodes in each input, hidden, output layer\n",
    "        self.inodes = inputnodes\n",
    "        self.hnodes = hiddennodes\n",
    "        self.onodes = outputnodes\n",
    "        \n",
    "        # link weight matrices, wih and who\n",
    "        # weights inside the arrays are w_i_j, where link is from node i to node j in the next layer\n",
    "        # w11 w21\n",
    "        # w12 w22 etc \n",
    "        self.wih = numpy.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))\n",
    "        self.who = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.onodes, self.hnodes))\n",
    "\n",
    "        # learning rate\n",
    "        self.lr = learningrate\n",
    "        \n",
    "        # activation function is the sigmoid function\n",
    "        self.activation_function = lambda x: scipy.special.expit(x)\n",
    "        \n",
    "        pass\n",
    "\n",
    "    \n",
    "    # train the neural network\n",
    "    def train(self, inputs_list, targets_list):\n",
    "        # convert inputs list to 2d array\n",
    "        inputs = numpy.array(inputs_list, ndmin=2).T\n",
    "        targets = numpy.array(targets_list, ndmin=2).T\n",
    "        \n",
    "        # calculate signals into hidden layer\n",
    "        hidden_inputs = numpy.dot(self.wih, inputs)\n",
    "        # calculate the signals emerging from hidden layer\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        \n",
    "        # calculate signals into final output layer\n",
    "        final_inputs = numpy.dot(self.who, hidden_outputs)\n",
    "        # calculate the signals emerging from final output layer\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        \n",
    "        # output layer error is the (target - actual)\n",
    "        output_errors = targets - final_outputs\n",
    "        # hidden layer error is the output_errors, split by weights, recombined at hidden nodes\n",
    "        hidden_errors = numpy.dot(self.who.T, output_errors) \n",
    "        \n",
    "        # update the weights for the links between the hidden and output layers\n",
    "        self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))\n",
    "        \n",
    "        # update the weights for the links between the input and hidden layers\n",
    "        self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))\n",
    "        \n",
    "        pass\n",
    "\n",
    "    \n",
    "    # query the neural network\n",
    "    def query(self, inputs_list):\n",
    "        # convert inputs list to 2d array\n",
    "        inputs = numpy.array(inputs_list, ndmin=2).T\n",
    "        \n",
    "        # calculate signals into hidden layer\n",
    "        hidden_inputs = numpy.dot(self.wih, inputs)\n",
    "        # calculate the signals emerging from hidden layer\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        \n",
    "        # calculate signals into final output layer\n",
    "        final_inputs = numpy.dot(self.who, hidden_outputs)\n",
    "        # calculate the signals emerging from final output layer\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        \n",
    "        return final_outputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# number of input, hidden and output nodes\n",
    "input_nodes = 784\n",
    "hidden_nodes = 200\n",
    "output_nodes = 10\n",
    "\n",
    "# learning rate\n",
    "learning_rate = 0.1\n",
    "\n",
    "# create instance of neural network\n",
    "n = neuralNetwork(input_nodes,hidden_nodes,output_nodes, learning_rate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# load the mnist training data CSV file into a list\n",
    "training_data_file = open(\"mnist_dataset/mnist_train.csv\", 'r')\n",
    "training_data_list = training_data_file.readlines()\n",
    "training_data_file.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# train the neural network\n",
    "\n",
    "# epochs is the number of times the training data set is used for training\n",
    "epochs = 10\n",
    "\n",
    "for e in range(epochs):\n",
    "    # go through all records in the training data set\n",
    "    for record in training_data_list:\n",
    "        # split the record by the ',' commas\n",
    "        all_values = record.split(',')\n",
    "        # scale and shift the inputs\n",
    "        inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01\n",
    "        # create the target output values (all 0.01, except the desired label which is 0.99)\n",
    "        targets = numpy.zeros(output_nodes) + 0.01\n",
    "        # all_values[0] is the target label for this record\n",
    "        targets[int(all_values[0])] = 0.99\n",
    "        n.train(inputs, targets)\n",
    "        pass\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loading ...  my_own_images/2828_my_own_3.png\n",
      "0.01\n",
      "0.97282356\n",
      "loading ...  my_own_images/2828_my_own_4.png\n",
      "0.01\n",
      "1.0\n"
     ]
    }
   ],
   "source": [
    "# our own image test data set\n",
    "our_own_dataset = []\n",
    "\n",
    "# load the png image data as test data set\n",
    "for image_file_name in glob.glob('my_own_images/2828_my_own_?.png'):\n",
    "    \n",
    "    # use the filename to set the correct label\n",
    "    label = int(image_file_name[-5:-4])\n",
    "    \n",
    "    # load image data from png files into an array\n",
    "    print (\"loading ... \", image_file_name)\n",
    "    img_array = imageio.v3.imread(image_file_name, mode='F')\n",
    "    \n",
    "    # reshape from 28x28 to list of 784 values, invert values\n",
    "    img_data  = 255.0 - img_array.reshape(784)\n",
    "    \n",
    "    # then scale data to range from 0.01 to 1.0\n",
    "    img_data = (img_data / 255.0 * 0.99) + 0.01\n",
    "    print(numpy.min(img_data))\n",
    "    print(numpy.max(img_data))\n",
    "    \n",
    "    # append label and image data  to test data set\n",
    "    record = numpy.append(label,img_data)\n",
    "    our_own_dataset.append(record)\n",
    "    \n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.00144122]\n",
      " [0.00628691]\n",
      " [0.0026605 ]\n",
      " [0.99757113]\n",
      " [0.00207352]\n",
      " [0.00342805]\n",
      " [0.00793897]\n",
      " [0.00169837]\n",
      " [0.01994708]\n",
      " [0.00951167]]\n",
      "network says  3\n",
      "match!\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# test the neural network with our own images\n",
    "\n",
    "# record to test\n",
    "item = 0\n",
    "\n",
    "# plot image\n",
    "matplotlib.pyplot.imshow(our_own_dataset[item][1:].reshape(28,28), cmap='Greys', interpolation='None')\n",
    "\n",
    "# correct answer is first value\n",
    "correct_label = our_own_dataset[item][0]\n",
    "# data is remaining values\n",
    "inputs = our_own_dataset[item][1:]\n",
    "\n",
    "# query the network\n",
    "outputs = n.query(inputs)\n",
    "print (outputs)\n",
    "\n",
    "# the index of the highest value corresponds to the label\n",
    "label = numpy.argmax(outputs)\n",
    "print(\"network says \", label)\n",
    "# append correct or incorrect to list\n",
    "if (label == correct_label):\n",
    "    print (\"match!\")\n",
    "else:\n",
    "    print (\"no match!\")\n",
    "    pass\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
